// Copyright (c) 2022 MASSA LABS <info@massa.net>

use massa_models::{
    block_id::BlockId,
    denunciation::{Denunciation, DenunciationPrecursor},
    endorsement::EndorsementId,
    operation::OperationId,
    slot::Slot,
};
use massa_storage::Storage;
use massa_time::MassaTime;

use crate::error::PoolError;

#[cfg(feature = "test-exports")]
use std::sync::{Arc, RwLock};

/// Trait defining a pool controller
#[cfg_attr(feature = "test-exports", mockall_wrap::wrap, mockall::automock)]
pub trait PoolController: Send + Sync {
    /// Asynchronously add operations to pool. Simply print a warning on failure.
    fn add_operations(&mut self, ops: Storage);

    /// Asynchronously add endorsements to pool. Simply print a warning on failure.
    fn add_endorsements(&mut self, endorsements: Storage);

    /// Add denunciation precursor to pool
    fn add_denunciation_precursor(&self, denunciation_precursor: DenunciationPrecursor);

    /// Asynchronously notify of new consensus final periods. Simply print a warning on failure.
    fn notify_final_cs_periods(&mut self, final_cs_periods: &[u64]);

    /// Get operations for block creation.
    fn get_block_operations(
        &self,
        slot: &Slot,
        timeout: Option<MassaTime>,
    ) -> Result<(Vec<OperationId>, Storage), PoolError>;

    /// Get endorsements for a block.
    fn get_block_endorsements(
        &self,
        target_block: &BlockId,
        slot: &Slot,
        timeout: Option<MassaTime>,
    ) -> Result<(Vec<Option<EndorsementId>>, Storage), PoolError>;

    /// Get denunciations for a block header.
    fn get_block_denunciations(
        &self,
        target_slot: &Slot,
        timeout: Option<MassaTime>,
    ) -> Result<Vec<Denunciation>, PoolError>;

    /// Get the number of endorsements in the pool
    fn get_endorsement_count(&self, timeout: Option<MassaTime>) -> Result<usize, PoolError>;

    /// Get the number of operations in the pool
    fn get_operation_count(&self, timeout: Option<MassaTime>) -> Result<usize, PoolError>;

    /// Check if the pool contains a list of endorsements. Returns one boolean per item.
    fn contains_endorsements(
        &self,
        endorsements: &[EndorsementId],
        timeout: Option<MassaTime>,
    ) -> Result<Vec<bool>, PoolError>;

    /// Check if the pool contains a list of operations. Returns one boolean per item.
    fn contains_operations(
        &self,
        operations: &[OperationId],
        timeout: Option<MassaTime>,
    ) -> Result<Vec<bool>, PoolError>;

    /// Get the number of denunciations in the pool
    fn get_denunciation_count(&self, timeout: Option<MassaTime>) -> Result<usize, PoolError>;

    /// Returns a boxed clone of self.
    /// Useful to allow cloning `Box<dyn PoolController>`.
    fn clone_box(&self) -> Box<dyn PoolController>;

    /// Get final cs periods (updated regularly from consensus)
    fn get_final_cs_periods(&self) -> Vec<u64>;
}

/// Allow cloning `Box<dyn PoolController>`
/// Uses `PoolController::clone_box` internally
impl Clone for Box<dyn PoolController> {
    fn clone(&self) -> Box<dyn PoolController> {
        self.clone_box()
    }
}

/// Pool manager trait
pub trait PoolManager: Send + Sync {
    /// Stops the worker
    fn stop(&mut self);
}
